home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c++-part1 / 4865 < prev    next >
Encoding:
Text File  |  1996-08-06  |  3.7 KB  |  103 lines

  1. Path: gidora.kralizec.net.au!not-for-mail
  2. From: bde@zeta.org.au (Bruce Evans)
  3. Newsgroups: comp.lang.c,comp.lang.c++,gnu.gcc.help,gnu.g++.help,comp.os.msdos.djgpp
  4. Subject: Re: float != float and floats as return types
  5. Date: 1 Feb 1996 23:38:13 +1100
  6. Organization: Kralizec Dialup Unix
  7. Message-ID: <4eqc7l$ugh@godzilla.zeta.org.au>
  8. References: <4ej9lb$mpc@fu-berlin.de> <4elnjj$er4@server2.rz.uni-leipzig.de>
  9. NNTP-Posting-Host: godzilla.zeta.org.au
  10.  
  11. In article <4elnjj$er4@server2.rz.uni-leipzig.de>,
  12. Steffen Winterfeldt <wfeldt@physik.uni-leipzig.de> wrote:
  13. >Axel Thimm (axl@zedat.fu-berlin.de) wrote:
  14. >: Hello,
  15. >: I am getting confused, about how C/C++ manage float binary operations,
  16. >: in particular multiplication. The next C++ example gives me surprising
  17. >: results:
  18. >:     *** cut here: begin file t_prec.cc
  19. >:     #include <iostream.h>
  20. >:     #include <iomanip.h>
  21. >:     #include <math.h>
  22. >:     float quad( float );
  23. >:     int main() {
  24. >:       for( int i=0; i<10; ++i ) {
  25. >:         float a, b, c;
  26. >:         a = i/13.123123;
  27. >:         b = a*a;
  28. >:         c = quad(a);
  29. >:         cout << (b - c) << '\t';
  30. >:         cout << (b - a*a) << '\t';
  31. >:         cout << (c - quad(a)) << '\n';
  32. >:       }
  33. >:       return 0;
  34. >:     }
  35. >:     float quad( float x ) { return x*x; }
  36. >: [...]
  37. >
  38. >(c - quad(a)) is not zero, because quad's return value is in a floating point
  39. >register and so has higher precision than c.
  40.  
  41. Wrong.
  42.  
  43. gcc's machine description for the i386 bogusly says that the result of a
  44. (float * float) calculation has float precision.  This is only true if
  45. the ambient precision is 24 bits or if -msoft-float is used.  Because of
  46. this, gcc omits the conversions that it would do if it had the correct
  47. precision (type) information.  It clips the extra precision for
  48. assignments from double variables or long double variables to float
  49. variables and for returning double or long double values from functions
  50. that return float, even if the value is originally in a floating point
  51. register and could end up in the same register.  The ANSI standard is
  52. ambiguous about whether these conversions must be done.  Anyway, gcc
  53. sometimes skips them not because it chooses the most convenient
  54. interpretation of the standard, but because of the bogus machine
  55. description.
  56.  
  57. (c - quad(a)) is nonzero because gcc decided to spill exactly one of the
  58. operands to memory.  Because it has the wrong precision (type) information,
  59. it spills to a float variable.  The spilled operand ends up correct and
  60. the unspilled value ends up wrong.
  61.  
  62. >BTW, with higher optimization (say, -O3), even the second column becomes zero.
  63.  
  64. This is wrong too.  The second column should never be zero if the
  65. ambient precision is double or long double and the assignment to b
  66. converts to float precision.  The higher optimization level probably
  67. allows the value of b to be kept in a register so that it doesn't happen
  68. to get clipped to float precision for the wrong reasons.
  69.  
  70. My standard example of the problem is:
  71. ---
  72. #include <assert.h>
  73. #include <float.h>
  74. #include <stdio.h>
  75.  
  76. int main(void)
  77. {
  78.     float volatile a, b, c;
  79.  
  80.     /*
  81.      * i386.md has a bogus addsf3 pattern (the result has long double
  82.      * precision, not float precision, unless the ambient precision is
  83.      * float), so some casts are elided.  All the variables have to be
  84.      * volatile so that the calculations don't get done at compile time.
  85.      * The compile-time calculations are correct and the whole test
  86.      * would get optimized away.
  87.      */
  88.     a = 1.0;
  89.     b = FLT_EPSILON / 4.0;
  90.     c = a + b;
  91.     assert(c == (float) (a + b));
  92.     return 0;
  93. }
  94. ---
  95.  
  96. If the ambient precision is 64 bits, as it is under Linux, then this
  97. problem also afflicts double precision vs. long double precision.
  98.  
  99. Fixing this problem for the i386 would have litte effect other than slowing
  100. down most floating point code :-(.
  101. -- 
  102. Bruce Evans  bde@zeta.org.au
  103.